home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1997 / MacHack 1997.toast / Hacks / Hacks ’95 / What's On My Mac / cgi.c < prev    next >
Text File  |  1995-06-24  |  21KB  |  803 lines

  1. /*****
  2.  *
  3.  *    Grant's CGI Shell (Common Grant Interface :-)
  4.  *
  5.  *    cgi.c
  6.  *
  7.  *    Standard functions for cgi applications.
  8.  *    You must call InitCGIUtil in your application startup.
  9.  *    You must install CGIAEHandle as the event handler for the WWWΩsdoc apple event
  10.  *    You must write the function:
  11.  *        void MyCGIProcess ( CGIHdl theCGIHdl )
  12.  *
  13.  *    by Grant Neufeld (with Scott T. Boyd and bits of other help from other people)
  14.  *        the original source that this was inspired by is "Responder" written by John O'Fallon
  15.  *        see his site: http://www.maxum.com/maxum/
  16.  *
  17.  *    watch my url for future upgrades
  18.  *
  19.  *    if you want notice of upgrades, subscribe to macwwwtool@arpp1.carelton.ca
  20.  *
  21.  *    http://arpp1.carleton.ca/grant/
  22.  *    gneufeld@ccs.carleton.ca
  23.  *    grant@acm.org
  24.  *
  25.  *    Copyright ©1995 by Grant Neufeld
  26.  *
  27.  *    This source may be freely used as long as the copyright notice is kept in the source.
  28.  *    I (we) ask that you let us know of any enhancements (read: bug fixes) to this code.
  29.  *    I (we) would also like copies of (or discounts on) anything you produce this with, please.
  30.  *
  31.  *****/
  32.  
  33. #include <stdlib.h>
  34. #include <string.h>
  35.  
  36. #include "DebugUtil.h"
  37. #include "MemoryUtil.h"
  38. #include "StringUtil.h"
  39.  
  40. #include "cgi.h"
  41.  
  42.  
  43. /***  CONSTANT DECLARATIONS  ***/
  44.  
  45. #define kHTTPHeaderStrs        129
  46. #define kHTTPHeaderOK        1
  47. #define kHTTPHeaderRedirect    2
  48. #define kHTTPHeaderErr        3
  49.  
  50.  
  51. /***  VARIABLE DECLARATIONS  ***/
  52.  
  53. /***  EXTERNAL FUNCTION PROTOTYPES  ***/
  54.  
  55.     void    MyCGIProcess        ( CGIHdl );
  56.  
  57.  
  58. /***  LOCAL FUNCTION PROTOTYPES  ***/
  59.  
  60.     OSErr    cgiAEGetParamString        ( AppleEvent *, AEKeyword, char **,         char *, long );
  61.     OSErr    cgiAEGetParamShort        ( AppleEvent *, AEKeyword, short *,         char *, long );
  62.     OSErr    cgiAEGetParamHTTPMethod    ( AppleEvent *, AEKeyword, HTTPMethod *, char *, long );
  63.  
  64.  
  65. /***  FUNCTIONS  ***/
  66.  
  67. /*  */
  68. void
  69. InitCGIUtil ( void )
  70. {
  71.     GetIndString ( gHTTPHeaderOK, kHTTPHeaderStrs, kHTTPHeaderOK );
  72.     P2CStr ( gHTTPHeaderOK );
  73.     gHTTPHeaderOKSize = strlen ( (char *)gHTTPHeaderOK );
  74.     
  75.     GetIndString ( gHTTPHeaderRedirect, kHTTPHeaderStrs, kHTTPHeaderRedirect );
  76.     P2CStr ( gHTTPHeaderRedirect );
  77.     gHTTPHeaderRedirectSize = strlen ( (char *)gHTTPHeaderRedirect );
  78.     
  79.     GetIndString ( gHTTPHeaderErr, kHTTPHeaderStrs, kHTTPHeaderErr );
  80.     P2CStr ( gHTTPHeaderErr );
  81.     gHTTPHeaderErrSize = strlen ( (char *)gHTTPHeaderErr );
  82. } /* InitCGIUtil */
  83.  
  84.  
  85. #pragma mark -
  86.  
  87. /*  */
  88. void
  89. CGIDisposeHandle ( CGIHdl theCGIHdl )
  90. {
  91.     if ( (*theCGIHdl)->path_args != nil )
  92.     {
  93.         DisposePtr ( (Ptr)((*theCGIHdl)->path_args) );
  94.     }
  95.     if ( (*theCGIHdl)->http_search_args != nil )
  96.     {
  97.         DisposePtr ( (Ptr)((*theCGIHdl)->http_search_args) );
  98.     }
  99.     if ( (*theCGIHdl)->username != nil )
  100.     {
  101.         DisposePtr ( (Ptr)((*theCGIHdl)->username) );
  102.     }
  103.     if ( (*theCGIHdl)->password != nil )
  104.     {
  105.         DisposePtr ( (Ptr)((*theCGIHdl)->password) );
  106.     }
  107.     if ( (*theCGIHdl)->from_user != nil )
  108.     {
  109.         DisposePtr ( (Ptr)((*theCGIHdl)->from_user) );
  110.     }
  111.     if ( (*theCGIHdl)->client_address != nil )
  112.     {
  113.         DisposePtr ( (Ptr)((*theCGIHdl)->client_address) );
  114.     }
  115.     if ( (*theCGIHdl)->post_args != nil )
  116.     {
  117.         DisposePtr ( (Ptr)((*theCGIHdl)->post_args) );
  118.     }
  119.     if ( (*theCGIHdl)->server_name != nil )
  120.     {
  121.         DisposePtr ( (Ptr)((*theCGIHdl)->server_name) );
  122.     }
  123.     if ( (*theCGIHdl)->script_name != nil )
  124.     {
  125.         DisposePtr ( (Ptr)((*theCGIHdl)->script_name) );
  126.     }
  127.     if ( (*theCGIHdl)->content_type != nil )
  128.     {
  129.         DisposePtr ( (Ptr)((*theCGIHdl)->content_type) );
  130.     }
  131.     if ( (*theCGIHdl)->referer != nil )
  132.     {
  133.         DisposePtr ( (Ptr)((*theCGIHdl)->referer) );
  134.     }
  135.     if ( (*theCGIHdl)->user_agent != nil )
  136.     {
  137.         DisposePtr ( (Ptr)((*theCGIHdl)->user_agent) );
  138.     }
  139.     if ( (*theCGIHdl)->action != nil )
  140.     {
  141.         DisposePtr ( (Ptr)((*theCGIHdl)->action) );
  142.     }
  143.     if ( (*theCGIHdl)->action_path != nil )
  144.     {
  145.         DisposePtr ( (Ptr)((*theCGIHdl)->action_path) );
  146.     }
  147.     if ( (*theCGIHdl)->client_ip != nil )
  148.     {
  149.         DisposePtr ( (Ptr)((*theCGIHdl)->client_ip) );
  150.     }
  151.     if ( (*theCGIHdl)->full_request != nil )
  152.     {
  153.         DisposePtr ( (Ptr)((*theCGIHdl)->full_request) );
  154.     }
  155.     
  156.     if ( (*theCGIHdl)->responseData != nil )
  157.     {
  158.         DisposePtr ( (Ptr)((*theCGIHdl)->responseData) );
  159.     }
  160.     
  161.     if ( (*theCGIHdl)->formFields != nil )
  162.     {
  163.         CGIFormFieldsDispose ( (*theCGIHdl)->formFields );
  164.     }
  165. } /* CGIDisposeHandle */
  166.  
  167.  
  168. #pragma mark -
  169.  
  170. /* The separator '&' separates individual fields.
  171.     The delimiter '=' delimits the name and value in a field.
  172.     Returns an array of field records with the last one containing null values. */
  173. CGIFormField *
  174. CGIFormFieldsFromArgs ( char *theString, long *count )
  175. {
  176.     CGIFormField *    theFields;
  177.     long            totalStrSize;
  178.     long            totalFields;
  179.     long            nameSize;
  180.     long            valueSize;
  181.     long            currentField;
  182.     char *            theStringPtr;
  183.     char *            fieldSeparator;
  184.     char *            fieldDelimiter;
  185.     
  186.     my_assert ( theString != nil, "CGIFormArgs: nil string" );
  187.     
  188.     theFields = nil;
  189.     
  190.     /* don't return number of fields until function is successful */
  191.     *count            = nil;
  192.     
  193.     totalStrSize    = strlen ( theString );
  194.     totalFields        = StringCountChar ( theString, kCGIFormFieldSeparator ) + 1;
  195.     
  196.     theFields        = (CGIFormField *) MyNewPtr ( ((totalFields + 1) * sizeof(CGIFormField)), nil );
  197.     
  198.     if ( theFields == nil )
  199.     {
  200.         goto Exit_Fail;
  201.     }
  202.     
  203.     (theFields[totalFields]).name    = nil;
  204.     (theFields[totalFields]).value    = nil;
  205.     
  206.     theStringPtr    = theString;
  207.     
  208.     for ( currentField = nil; currentField < totalFields; currentField++ )
  209.     {
  210.         fieldDelimiter    = strchr ( theStringPtr, kCGIFormFieldDelimiter );
  211.         fieldSeparator    = strchr ( theStringPtr, kCGIFormFieldSeparator );
  212.         
  213.         /* if there is a field delimiter, and it is before any field separator */
  214.         if ( (fieldDelimiter != nil) && ((fieldSeparator > fieldDelimiter) || (fieldSeparator == nil)) )
  215.         {
  216.             /* field name */
  217.             /* the size of the name string is the difference between the begining of the
  218.                 field and the position of the field delimiter */
  219.             nameSize = fieldDelimiter - theStringPtr;
  220.             
  221.             /* allocate the name string */
  222.             (theFields[currentField]).name = (char *) MyNewPtr ( nameSize + 1, nil );
  223.             
  224.             if ( (theFields[currentField]).name == nil )
  225.             {
  226.                 (theFields[currentField]).value = nil;
  227.                 goto Exit_Fail;
  228.             }
  229.             
  230.             /* copy the field name */
  231.             BlockMove ( theStringPtr, (theFields[currentField]).name, nameSize );
  232.             /* null terminate the end of the name string */
  233.             ((theFields[currentField]).name)[nameSize] = nil;
  234.             /* convert the url encoded text to a normal string */
  235.             CGIDecodeSpecialChars ( (theFields[currentField]).name );
  236.             
  237.             /* field value */
  238.             if ( fieldSeparator != nil )
  239.             {
  240.                 valueSize = fieldSeparator - (fieldDelimiter + 1);
  241.             }
  242.             else
  243.             {
  244.                 valueSize = strlen ( fieldDelimiter + 1 );
  245.             }
  246.             
  247.             (theFields[currentField]).value = (char *) MyNewPtr ( (valueSize + 1), nil );
  248.             
  249.             if ( (theFields[currentField]).value == nil )
  250.             {
  251.                 DisposePtr ( (theFields[currentField]).name );
  252.                 (theFields[currentField]).name = nil;
  253.                 
  254.                 goto Exit_Fail;
  255.             }
  256.             
  257.             BlockMove ( fieldDelimiter + 1, (theFields[currentField]).value, valueSize );
  258.             ((theFields[currentField]).value)[valueSize] = nil;
  259.             CGIDecodeSpecialChars ( (theFields[currentField]).value );
  260.             
  261.             theStringPtr = fieldSeparator + 1;
  262.         }
  263.         else
  264.         {
  265.             /* invalid data encountered, abort function */
  266.             goto Exit_Fail;
  267.         }
  268.     }
  269.     
  270.     *count = totalFields;
  271.     
  272.     return theFields;
  273.     
  274.     
  275.     Exit_Fail:
  276.     
  277.     if ( theFields != nil )
  278.     {
  279.         /* release allocated memory */
  280. //        CGIFormFieldsDispose ( theFields );
  281.     }
  282.     
  283.     return nil;
  284. } /* CGIFormFieldsFromArgs */
  285.  
  286.  
  287. /*  */
  288. CGIFormField *
  289. CGIFormFieldsFindRecord ( CGIFormField *fieldArray, char *fieldName )
  290. {
  291.     long            currentField;
  292.     
  293.     /* look til we find something or we hit the end */
  294.     for ( currentField = nil; (fieldArray[currentField]).name != nil; currentField++ )
  295.     {
  296.         if ( strcmp((fieldArray[currentField]).name, fieldName) == nil )
  297.         {
  298.             /* found a match */
  299.             return &(fieldArray[currentField]);
  300.         }
  301.     }
  302.     
  303.     /* didn't find a match */
  304.     return nil;
  305. } /* CGIFormFieldsFindRecord */
  306.  
  307.  
  308. /* Deallocate memory for theFields array */
  309. void
  310. CGIFormFieldsDispose ( CGIFormField *theFields )
  311. {
  312.     long    offset;
  313.     
  314.     my_assert ( theFields != nil, "CGIFormFieldsDispose: null field array pointer" );
  315.     
  316.     offset = nil;
  317.     
  318.     while ( true )
  319.     {
  320.         if ( (theFields[offset]).name == nil )
  321.         {
  322.             /* terminating field reached */
  323.             DisposePtr ( (Ptr)theFields );
  324.             return;
  325.         }
  326.         
  327.         DisposePtr ( (Ptr)((theFields[offset]).name) );
  328.         
  329.         if ( (theFields[offset]).value == nil )
  330.         {
  331.             DisposePtr ( (Ptr)((theFields[offset]).value) );
  332.         }
  333.         
  334.         offset++;
  335.     }
  336. } /* CGIFormFieldsDispose */
  337.  
  338. #pragma mark -
  339.  
  340. /* replaces instances of percent signs (%) followed by an ASCII char value
  341.     with the actual character */
  342. void
  343. CGIDecodeSpecialChars ( char *theString )
  344. {
  345.     int        read;
  346.     int        write;
  347.     int        AsciiChar;
  348.     
  349.     my_assert ( theString != nil, "CGIDecodeSpecialChars: nil string" );
  350.     
  351.     read    = nil;
  352.     write    = nil;
  353.     
  354.     while ( theString[read] != nil )
  355.     {
  356.         // Search the entire text block
  357.         switch ( theString[read] )
  358.         {
  359.             case '%':
  360.                 // if the char is a percent sign, look at the next char
  361.                 if ( (theString[read+1] >= 'A') && (theString[read+1] <= 'F') )
  362.                 {
  363.                     // convert A thru F to 10 thru 15
  364.                     AsciiChar = theString[read+1] - 'A' + 10;
  365.                 }
  366.                 else if ( (theString[read+1] >= 'a') && (theString[read+1] <= 'f') )
  367.                 {
  368.                     // convert a thru f to 10 thru 15
  369.                     AsciiChar = theString[read+1] - 'a' + 10;
  370.                 }
  371.                 else
  372.                 {
  373.                     // Convert all others to 0 to 9
  374.                     AsciiChar = theString[read+1] - '0';
  375.                 }
  376.                 
  377.                 // That was the high order of a hex number, so mult by 16 to find the decimal value.
  378.                 AsciiChar = AsciiChar * 16;
  379.                 
  380.                 // Now do the low order char...
  381.                 if ( (theString[read+2] >= 'A') && (theString[read+2] <= 'F') )
  382.                 {
  383.                     // Convert A thru F to 10 thru 15 (and add it to the high order value)
  384.                     AsciiChar += (theString[read+2] - 'A' + 10);
  385.                 }
  386.                 else if ( (theString[read+2] >= 'a') && (theString[read+2] <= 'f') )
  387.                 {
  388.                     // Convert a thru f to 10 thru 15 (and add it to the high order value)
  389.                     AsciiChar += (theString[read+2] - 'a' + 10);
  390.                 }
  391.                 else
  392.                 {
  393.                     // Convert all others to 0 to 9 (and add it to the high order value)
  394.                     AsciiChar += (theString[read+2] - '0');
  395.                 }
  396.                 
  397.                 if ((AsciiChar >= 0) && (AsciiChar < 256))
  398.                 {
  399.                     // if we got a valid value, replace the ASCII char
  400.                     if ( AsciiChar == 10 )
  401.                     {
  402.                         /* don't write newline */
  403.                         write--;
  404.                     }
  405.                     else
  406.                     {
  407.                         // Copy the char into the string
  408.                         theString[write] = AsciiChar;
  409.                     }
  410.                     
  411.                     // Now that we have converted them, skip the extra characters
  412.                     read += 2;
  413.                 }
  414.                 else
  415.                 {
  416.                     // False alarm, nothing to convert, just copy the char (shouldn't happen)
  417.                     theString[write] = theString[read];
  418.                 }
  419.                 break;
  420.             
  421.             case '+':
  422.                 // Spaces are coded as plus signs
  423.                 theString[write] = ' ';
  424.                 break;
  425.                 
  426.             case 10:
  427.                 // Strip out linefeeds, Macs don't use them
  428.                 write--;
  429.                 break;
  430.                 
  431.             default:
  432.                 // A normal character, just copy it
  433.                 theString[write] = theString[read];
  434.                 break;
  435.         }
  436.             
  437.         read++;
  438.         write++;
  439.     }
  440.     
  441.     // make sure the string is capped
  442.     theString[write] = '\0';
  443. } /* CGIDecodeSpecialChars */
  444.  
  445.  
  446. #define kCGIEncodeExtraChars        16
  447.  
  448. /* %hex encode all chars > 127 */
  449. char *
  450. CGIEncodeSpecialChars ( char *theString )
  451. {
  452.     char *    theResult;
  453.     long    strSize;
  454.     long    tempSize;
  455.     long    strOffset;
  456.     long    resOffset;
  457.     
  458.     strSize        = strlen ( theString );
  459.     tempSize    = strSize + kCGIEncodeExtraChars;
  460.     theResult    = (char *) MyNewPtr ( (tempSize + 1), nil );
  461.     
  462.     for ( strOffset = resOffset = nil; strOffset < strSize; strOffset++, resOffset++ )
  463.     {
  464.         if ( resOffset > tempSize )
  465.         {
  466.             tempSize += kCGIEncodeExtraChars;
  467.             SetPtrSize ( (Ptr)theResult, tempSize + 1 );
  468.         }
  469.         
  470.         if ( theString[strOffset] < 128 )
  471.         {
  472.             /* if the character is normal ascii, not high-bit, just copy it */
  473.             theResult[resOffset] = theString[strOffset];
  474.         }
  475.         else
  476.         {
  477.             if ( (resOffset + 2) > tempSize )
  478.             {
  479.                 tempSize += kCGIEncodeExtraChars;
  480.                 SetPtrSize ( (Ptr)theResult, tempSize + 1 );
  481.             }
  482.         
  483.             /* character is high-bit, encode it */
  484.             CGICharToHex ( theString[strOffset], &(theResult[resOffset]) );
  485.             /* add the extra two characters for hex encoding to the result offset */
  486.             resOffset += 2;
  487.         }
  488.     }
  489.     
  490.     if ( resOffset != tempSize )
  491.     {
  492.         SetPtrSize ( (Ptr)theResult, resOffset + 1 );
  493.     }
  494.     
  495.     return theResult;
  496. } /* CGIEncodeSpecialChars */
  497.  
  498.  
  499. /*  */
  500. void
  501. CGICharToHex ( unsigned char theChar, char *theString )
  502. {
  503.     unsigned char    tmpChr;
  504.     
  505.     theString[0]    = '%';
  506.     
  507.     /* high 4 bits */
  508.     tmpChr            = ( theChar & 0xF0 ) >> 4;
  509.     theString[1]    = ( tmpChr > 9 )?
  510.                         ( tmpChr - 10 ) +'A' :
  511.                         tmpChr + '0';
  512.     
  513.     /* low 4 bits */
  514.     tmpChr            = theChar & 0x0F;
  515.     theString[2]    = ( tmpChr > 9 )?
  516.                         ( tmpChr - 10 ) + 'A' :
  517.                         tmpChr + '0';
  518. } /* CGICharToHex */
  519.  
  520.  
  521. #pragma mark -
  522.  
  523. #pragma segment AppleEvent
  524. /* AppleEvent Handler for the CGI WWWΩ-sdoc event */
  525. pascal OSErr
  526. CGIAEHandle ( AppleEvent *theAppleEvent, AppleEvent *TheReply, long Reference )
  527. {
  528.     OSErr        theErr;
  529.     DescType    actualType;
  530.     Ptr            tempBuffer;
  531.     CGIHdl        theCGIHdl;
  532.     
  533.     theCGIHdl    = ( CGIHdl ) MyNewHandleClear ( sizeof(CGIrecord), &theErr );
  534.     
  535.     if ( theCGIHdl == nil )
  536.     {
  537.         return theErr;
  538.     }
  539.     
  540.     /* store references to the apple event and reply records */
  541.     (*theCGIHdl)->appleEvent    = theAppleEvent;
  542.     (*theCGIHdl)->replyEvent    = TheReply;
  543.     
  544.     tempBuffer    = MyNewPtr ( kCGIParamMaxSize, &theErr );
  545.     
  546.     if ( tempBuffer == nil )
  547.     {
  548.         DisposeHandle ( (Handle)theCGIHdl );
  549.         
  550.         return theErr;
  551.     }
  552.     
  553.     actualType = ( DescType ) 'char';
  554.     
  555.     HLockHi ( (Handle)theCGIHdl );
  556.     
  557.     /* '----' - direct parameter:
  558.         path_args - arguments to the URL after a $ */
  559.     theErr = cgiAEGetParamString ( theAppleEvent, '----', &((*theCGIHdl)->path_args),
  560.         (char *)tempBuffer, kCGIParamMaxSize );
  561.     if ( theErr == noErr )
  562.     {
  563.         CGIDecodeSpecialChars ( (*theCGIHdl)->path_args );
  564.     }
  565.     
  566.     /* 'kfor' - search arguments:
  567.         http_search_args - arguments to the URL after a ? */
  568.     theErr = cgiAEGetParamString ( theAppleEvent, kCGIhttp_search_args, &((*theCGIHdl)->http_search_args),
  569.         (char *)tempBuffer, kCGIParamMaxSize );
  570.     /* leave decoding to after parsing of form fields */
  571.     
  572.     /* 'user' - user name:
  573.         username - authenticated user name */
  574.     theErr = cgiAEGetParamString ( theAppleEvent, kCGIusername, &((*theCGIHdl)->username),
  575.         (char *)tempBuffer, kCGIParamMaxSize );
  576.     
  577.     /* 'pass' - password:
  578.         password - authenticated password */
  579.     theErr = cgiAEGetParamString ( theAppleEvent, kCGIpassword, &((*theCGIHdl)->password),
  580.         (char *)tempBuffer, kCGIParamMaxSize );
  581.     
  582.     /* 'frmu' - from user:
  583.         from_user - non-standard. e-mail address of remote user */
  584.     theErr = cgiAEGetParamString ( theAppleEvent, kCGIfrom_user, &((*theCGIHdl)->from_user),
  585.         (char *)tempBuffer, kCGIParamMaxSize );
  586.     
  587.     /* 'addr' - client address:
  588.         client_address - IP address or domain name of remote client's host */
  589.     theErr = cgiAEGetParamString ( theAppleEvent, kCGIclient_address, &((*theCGIHdl)->client_address),
  590.         (char *)tempBuffer, kCGIParamMaxSize );
  591.     
  592.     /* 'post' - post arguments:
  593.         post_args -  */
  594.     theErr = cgiAEGetParamString ( theAppleEvent, kCGIpost_args, &((*theCGIHdl)->post_args),
  595.         (char *)tempBuffer, kCGIParamMaxSize );
  596.     /* leave decoding to after parsing of form fields */
  597.     
  598.     /* 'meth' - HTTP method:
  599.         method - GET, POST, etc. Used to tell if post_args are valid */
  600.     theErr = cgiAEGetParamHTTPMethod ( theAppleEvent, kCGImethod, &((*theCGIHdl)->method),
  601.         (char *)tempBuffer, kCGIParamMaxSize );
  602.     
  603.     /* 'svnm' - server name:
  604.         server_name - name or IP address of this server */
  605.     theErr = cgiAEGetParamString ( theAppleEvent, kCGIserver_name, &((*theCGIHdl)->server_name),
  606.         (char *)tempBuffer, kCGIParamMaxSize );
  607.     
  608.     /* 'svpt' - server port:
  609.         server_port - TCP/IP port number being used by this server */
  610.     theErr = cgiAEGetParamShort ( theAppleEvent, kCGIserver_port, &((*theCGIHdl)->server_port),
  611.         (char *)tempBuffer, kCGIParamMaxSize );
  612.     
  613.     /* 'scnm' - script name:
  614.         script_name - URL name of this script */
  615.     theErr = cgiAEGetParamString ( theAppleEvent, kCGIscript_name, &((*theCGIHdl)->script_name),
  616.         (char *)tempBuffer, kCGIParamMaxSize );
  617.     
  618.     /* 'ctyp' - content type:
  619.         content_type - MIME content type of post_args */
  620.     theErr = cgiAEGetParamString ( theAppleEvent, kCGIcontent_type, &((*theCGIHdl)->content_type),
  621.         (char *)tempBuffer, kCGIParamMaxSize );
  622.     
  623.     /* 'refr' - referer:
  624.         referer - the URL of the page referencing this document */
  625.     theErr = cgiAEGetParamString ( theAppleEvent, kCGIreferer, &((*theCGIHdl)->referer),
  626.         (char *)tempBuffer, kCGIParamMaxSize );
  627.     
  628.     /* 'Agnt' - user agent:
  629.         user_agent - the name and version of the WWW client software being used */
  630.     theErr = cgiAEGetParamString ( theAppleEvent, kCGIuser_agent, &((*theCGIHdl)->user_agent),
  631.         (char *)tempBuffer, kCGIParamMaxSize );
  632.     
  633.     /* 'Kact' - action name:
  634.         action - the name of the action (CGI or ACGI if not a user defined action) */
  635.     theErr = cgiAEGetParamString ( theAppleEvent, kCGIaction, &((*theCGIHdl)->action),
  636.         (char *)tempBuffer, kCGIParamMaxSize );
  637.     
  638.     /* 'Kapt' - action path:
  639.         action_path - path to the action application */
  640.     theErr = cgiAEGetParamString ( theAppleEvent, kCGIaction_path, &((*theCGIHdl)->action_path),
  641.         (char *)tempBuffer, kCGIParamMaxSize );
  642.     
  643.     /* 'Kcip' - client IP address:
  644.         client_ip - the IP address of the client */
  645.     theErr = cgiAEGetParamString ( theAppleEvent, kCGIclient_ip, &((*theCGIHdl)->client_ip),
  646.         (char *)tempBuffer, kCGIParamMaxSize );
  647.     
  648.     /* 'Kfrq' - full request:
  649.         full_request - the full text of the request */
  650.     theErr = cgiAEGetParamString ( theAppleEvent, kCGIfull_request, &((*theCGIHdl)->full_request),
  651.         (char *)tempBuffer, kCGIParamMaxSize );
  652.     
  653.     /* separate the form fields into an array */
  654.     switch ( (*theCGIHdl)->method )
  655.     {
  656.         case HTTP_get :
  657.             if ( (*theCGIHdl)->http_search_args != nil )
  658.             {
  659.                 (*theCGIHdl)->formFields = CGIFormFieldsFromArgs ( (*theCGIHdl)->http_search_args, &((*theCGIHdl)->totalFields) );
  660.             }
  661.             break;
  662.             
  663.         case HTTP_post :
  664.         default :
  665.             if ( (*theCGIHdl)->post_args != nil )
  666.             {
  667.                 (*theCGIHdl)->formFields = CGIFormFieldsFromArgs ( (*theCGIHdl)->post_args, &((*theCGIHdl)->totalFields) );
  668.             }
  669.             break;
  670.     }
  671.     
  672.     /* now that the need to use them for form fields is over, we can
  673.         decode the search args */
  674.     CGIDecodeSpecialChars ( (*theCGIHdl)->http_search_args );
  675.     
  676.     /* this is where the application specific cgi handling comes into play */
  677.     HUnlock            ( (Handle)theCGIHdl );
  678.     MyCGIProcess    ( theCGIHdl );
  679.     HLock            ( (Handle)theCGIHdl );
  680.     
  681.     if ( (*theCGIHdl)->responseData != nil )
  682.     {
  683.         theErr = AEPutParamPtr ( TheReply, keyDirectObject, typeChar,
  684.             (Ptr)((*theCGIHdl)->responseData), (*theCGIHdl)->responseSize );
  685.     }
  686.     else
  687.     {
  688.         theErr = AEPutParamPtr ( TheReply, keyDirectObject, typeChar, (Ptr)gHTTPHeaderErr, gHTTPHeaderErrSize );
  689.     }
  690.     
  691.     HUnlock ( (Handle)theCGIHdl );
  692.     
  693.     /* deallocate memory */
  694.     CGIDisposeHandle ( theCGIHdl );
  695.     
  696.     return theErr;
  697. } /* CGIAEHandle */
  698.  
  699.  
  700. #pragma segment AppleEvent
  701. /*  */
  702. OSErr
  703. cgiAEGetParamString ( AppleEvent *theAppleEvent, AEKeyword theAEKeyword, char **theString, char *tempBuffer, long bufferSize )
  704. {
  705.     OSErr        theErr;
  706.     DescType    actualType;
  707.     Size        actualSize;
  708.     
  709.     my_assert ( *theString == nil, "cgiAEGetParamString: non-nil string received" );
  710.     
  711.     theErr = AEGetParamPtr
  712.         ( theAppleEvent, theAEKeyword, typeChar, &actualType, (Ptr)tempBuffer, bufferSize, &actualSize );
  713.     
  714.     if ( theErr == noErr )
  715.     {
  716.         *theString = (char *) MyNewPtr ( actualSize + 1, &theErr );
  717.         
  718.         if ( *theString != nil )
  719.         {
  720.             /* copy the tempBuffer into the CGI handle */
  721.             BlockMove ( tempBuffer, *theString, actualSize );
  722.             
  723.             /* put a null terminator at the end of the string */
  724.             (*theString)[actualSize] = nil;
  725.         }
  726.     }
  727.     
  728.     return theErr;
  729. } /* cgiAEGetParamString */
  730.  
  731.  
  732. #pragma segment AppleEvent
  733. /*  */
  734. OSErr
  735. cgiAEGetParamShort ( AppleEvent *theAppleEvent, AEKeyword theAEKeyword, short *theShort, char *tempBuffer, long bufferSize )
  736. {
  737.     OSErr        theErr;
  738.     DescType    actualType;
  739.     Size        actualSize;
  740.     
  741.     theErr = AEGetParamPtr
  742.         ( theAppleEvent, theAEKeyword, typeChar, &actualType, (Ptr)tempBuffer, bufferSize, &actualSize );
  743.     
  744.     if ( theErr == noErr )
  745.     {
  746.         /* terminate the buffer with a null byte */
  747.         tempBuffer[actualSize] = nil;
  748.         
  749.         *theShort = atoi ( tempBuffer );
  750.     }
  751.     
  752.     return theErr;
  753. } /* cgiAEGetParamShort */
  754.  
  755.  
  756. #pragma segment AppleEvent
  757. /*  */
  758. OSErr
  759. cgiAEGetParamHTTPMethod ( AppleEvent *theAppleEvent, AEKeyword theAEKeyword, HTTPMethod *theMethod, char *tempBuffer, long bufferSize )
  760. {
  761.     OSErr        theErr;
  762.     DescType    actualType;
  763.     Size        actualSize;
  764.     int            stringDiff;
  765.     
  766.     theErr = AEGetParamPtr
  767.         ( theAppleEvent, theAEKeyword, typeChar, &actualType, (Ptr)tempBuffer, bufferSize, &actualSize );
  768.     
  769.     if ( theErr == noErr )
  770.     {
  771.         /* terminate the buffer with a null byte */
  772.         tempBuffer[actualSize] = nil;
  773.         
  774.         /* compare the buffer with constants to determine the http method used */
  775.         stringDiff = strcmp ( tempBuffer, kCGIHTTPMethodGet );
  776.         
  777.         if ( stringDiff == nil )
  778.         {
  779.             *theMethod = HTTP_get;
  780.         }
  781.         else
  782.         {
  783.             stringDiff = strcmp ( tempBuffer, kCGIHTTPMethodPost );
  784.             
  785.             if ( stringDiff == nil )
  786.             {
  787.                 *theMethod = HTTP_post;
  788.             }
  789.             else
  790.             {
  791.                 *theMethod = HTTP_UNDEFINED;
  792.             }
  793.         }
  794.     }
  795.     
  796.     return theErr;
  797. } /* cgiAEGetParamHTTPMethod */
  798.  
  799.  
  800. #pragma segment Main
  801.  
  802. /***  EOF  ***/
  803.